package com.xjrsoft.module.generator.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.meta.Column;
import cn.hutool.db.meta.Table;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.common.model.generator.ComponentConfig;
import com.xjrsoft.common.model.generator.LayoutOptionModel;
import com.xjrsoft.common.utils.ExcelUtil;
import com.xjrsoft.common.utils.JdbcToJavaUtil;
import com.xjrsoft.common.utils.LocalDateTimeUtil;
import com.xjrsoft.module.generator.constant.ComponentTypeConstant;
import com.xjrsoft.module.generator.constant.EntityConstant;
import com.xjrsoft.module.generator.entity.*;
import freemarker.template.Template;
import lombok.SneakyThrows;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

public final class GeneratorUtil {

    private static final String ENTITY_TEMPLATE_NAME = "entity.java.ftl";

    private static final String ADD_DTO_TEMPLATE_NAME = "add.dto.java.ftl";

    private static final String UPDATE_DTO_TEMPLATE_NAME = "update.dto.java.ftl";

    private static final String PAGE_DTO_TEMPLATE_NAME = "page.list.dto.java.ftl";

    private static final String PAGE_VO_TEMPLATE_NAME = "page.list.vo.java.ftl";

    private static final String INFO_VO_TEMPLATE_NAME = "vo.java.ftl";

    private static final String MAPPPER_TEMPLATE_NAME = "mapper.java.ftl";

    private static final String SERVICE_TEMPLATE_NAME = "service.java.ftl";

    private static final String SERVICE_IMPL_TEMPLATE_NAME = "service.impl.java.ftl";

    private static final String CONTROLLER_TEMPLATE_NAME = "controller.java.ftl";
    private GeneratorUtil(){}

    public static Map<String, List<ComponentConfig>> buildFormComponentList(List<ComponentConfig> sourceList) {
        Map<String, List<ComponentConfig>> resultMap = new CaseInsensitiveKeyMap<>();
        buildFormComponentList(resultMap, sourceList);
        return resultMap;
    }

    public static void buildFormComponentList(Map<String, List<ComponentConfig>> targetMap, List<ComponentConfig> sourceList) {
        for (ComponentConfig config : sourceList) {
            String type = config.getType();
            if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.SUB_FORM) || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.ONE_FOR_ONE_FORM)) {
                List<ComponentConfig> children = config.getChildren();
                buildFormComponentList(targetMap, children);
            } else if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.TAB)
                    || StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.CARD)
                    || StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.GRID)) {
                List<LayoutOptionModel> tabList = config.getLayout();
                for (LayoutOptionModel tab : tabList) {
                    List<ComponentConfig> tabComponentList = tab.getList();
                    buildFormComponentList(targetMap, tabComponentList);
                }
            } else if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.TABLE_LAYOUT)) {
                List<LayoutOptionModel> tabList = config.getLayout();
                for (LayoutOptionModel tab : tabList) {
                    List<ComponentConfig> tabComponentList = tab.getList();
                    for (ComponentConfig cellComponentConfig : tabComponentList) {
                        List<ComponentConfig> children = cellComponentConfig.getChildren();
                        buildFormComponentList(targetMap, children);
                    }
                }
            } else {
                String bindTable = config.getBindTable();
                if (StrUtil.isNotBlank(bindTable) && (StrUtil.isNotBlank(config.getBindField())
                        || (StrUtil.isNotBlank(config.getBindStartTime()) && StrUtil.isNotBlank(config.getBindEndTime())))) {
                    List<ComponentConfig> componentConfigList = targetMap.computeIfAbsent(bindTable, k -> new ArrayList<>());
                    componentConfigList.add(config);
                }
            }
        }
    }

    public static List<ComponentConfig> getFormComponentListWithoutLayout(List<ComponentConfig> sourceList) {
        List<ComponentConfig> resultList = new ArrayList<>();
        for (ComponentConfig config : sourceList) {
            String type = config.getType();
            if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.TAB)
                    || StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.CARD)
                    || StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.GRID)) {
                List<LayoutOptionModel> tabList = config.getLayout();
                for (LayoutOptionModel tab : tabList) {
                    List<ComponentConfig> tabComponentList = tab.getList();
                    resultList.addAll(getFormComponentListWithoutLayout(tabComponentList));
                }
            } else if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.TABLE_LAYOUT)) {
                List<LayoutOptionModel> tabList = config.getLayout();
                for (LayoutOptionModel tab : tabList) {
                    List<ComponentConfig> tabComponentList = tab.getList();
                    for (ComponentConfig cellComponentConfig : tabComponentList) {
                        List<ComponentConfig> children = cellComponentConfig.getChildren();
                        resultList.addAll(getFormComponentListWithoutLayout(children));
                    }
                }
            } else {
                resultList.add(config);
            }
        }
        return resultList;
    }

    public static List<ComponentConfig> getFormComponentListWithMain(List<ComponentConfig> sourceList) {
        List<ComponentConfig> resultList = new ArrayList<>();
        for (ComponentConfig config : sourceList) {
            String type = config.getType();
            if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.SUB_FORM) || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.ONE_FOR_ONE_FORM)) {
                continue;
            } else if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.TAB)
                    || StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.CARD)
                    || StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.GRID)) {
                List<LayoutOptionModel> tabList = config.getLayout();
                for (LayoutOptionModel tab : tabList) {
                    List<ComponentConfig> tabComponentList = tab.getList();
                    resultList.addAll(getFormComponentListWithMain(tabComponentList));
                }
            } else if (StringUtils.equalsIgnoreCase(type, ComponentTypeConstant.TABLE_LAYOUT)) {
                List<LayoutOptionModel> tabList = config.getLayout();
                for (LayoutOptionModel tab : tabList) {
                    List<ComponentConfig> tabComponentList = tab.getList();
                    for (ComponentConfig cellComponentConfig : tabComponentList) {
                        List<ComponentConfig> children = cellComponentConfig.getChildren();
                        resultList.addAll(getFormComponentListWithMain(children));
                    }
                }
            } else {
                String bindTable = config.getBindTable();
                if (StrUtil.isNotBlank(bindTable) && (StrUtil.isNotBlank(config.getBindField())
                        || (StrUtil.isNotBlank(config.getBindStartTime()) && StrUtil.isNotBlank(config.getBindEndTime())))) {
                    resultList.add(config);
                }
            }
        }
        return resultList;
    }

    /**
     * 根据配置生成实体类代码
     *
     * @param generatorConfig 入参
     * @param tableInfos      表信息
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getEntityCode(GeneratorConfig generatorConfig, List<Table> tableInfos) {
        Map<String, String> entityCodeMap = new HashMap<>(tableInfos.size());
        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
        for (Table tableInfo : tableInfos) {
            //获取表的所有字段
            Collection<Column> columns = tableInfo.getColumns();
            List<FieldConfig> fieldConfigList = new ArrayList<>();

            for (Column column : columns) {
                FieldConfig fieldConfig = new FieldConfig();

                if (GlobalConstant.AUTO_INSERT.contains(StringUtils.lowerCase(column.getName()))) {
                    fieldConfig.setAutoInsert(true);
                }

                if (GlobalConstant.AUTO_UPDATE.contains(StringUtils.lowerCase(column.getName()))) {
                    fieldConfig.setAutoUpdate(true);
                }

                if (StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)) {
                    fieldConfig.setDeleteMark(true);
                }
                fieldConfig.setFieldComment(column.getComment());
                fieldConfig.setPk(column.isPk());
                fieldConfig.setFieldType(JdbcToJavaUtil.getClassName(column));
                fieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(column.getName()));

                fieldConfigList.add(fieldConfig);

            }


            //如果有子表  每多一个子表  多加1个长度
            Map<String, Object> entityMap = new HashMap<>(8);
            entityMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "entity");
            entityMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
            entityMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            entityMap.put(EntityConstant.TABLE_NAME, tableInfo.getTableName());
            entityMap.put(EntityConstant.TABLE_COMMENT, generatorConfig.getOutputConfig().getComment());
            //先将表明转换为驼峰命名 然后在转换为首字母大写
            entityMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
            entityMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
            entityMap.put(EntityConstant.IS_COMMON_FIELDS, generatorConfig.getOutputConfig().getIsCommonFields());

            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
            boolean isMainTable = generatorConfig.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
            if (tableInfos.size() > 1 && isMainTable) {
                List<TableConfig> childTables = generatorConfig.getTableConfigs().stream()
                        .filter(x -> !x.getIsMain())
                        .collect(Collectors.toList());

                List<TableConfig> newChildTables = new ArrayList<>();
                for (TableConfig childTable : childTables) {
                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);

                    newTableConfig.setRelationField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationField()));
                    newTableConfig.setRelationTableField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationTableField()));
                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));

                    newChildTables.add(newTableConfig);
                }
//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
                entityMap.put(EntityConstant.CHILD_TABLES, newChildTables);
//                parentTable.ifPresent(x -> entityMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
            }


            //生产目标代码
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//            Template template = configuration.getTemplate(ENTITY_TEMPLATE_NAME);


            FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(ENTITY_TEMPLATE_NAME);
            String entityContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, entityMap);

            entityCodeMap.put(StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())), entityContent);
        }

        return entityCodeMap;
    }

    /**
     * 根据配置新增dto代码
     *
     * @param generatorConfig 入参
     * @param tableInfos      表信息
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getAddDtoCode(GeneratorConfig generatorConfig, List<Table> tableInfos) {
        Map<String, String> addCodeMap = new HashMap<>(tableInfos.size());
        Map<String, List<ComponentConfig>> tableFieldListMap = GeneratorUtil.buildFormComponentList(generatorConfig.getFormJson().getList());
        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
        for (Table tableInfo : tableInfos) {
            //获取表的所有字段
            Collection<Column> columnList = tableInfo.getColumns();

            List<FieldConfig> fieldConfigList = new ArrayList<>();

            List<ComponentConfig> componentConfigList = tableFieldListMap.get(tableInfo.getTableName());
            for (Column column : columnList) {
                FieldConfig fieldConfig = new FieldConfig();

                //因为是新增Dto  不需要主键
                if (column.isPk()) {
                    continue;
                }

                //不属于 固定的审计字段 都需要生成
                if (
                        !GlobalConstant.AUTO_INSERT.contains(column.getName()) &&
                                !GlobalConstant.AUTO_UPDATE.contains(column.getName()) &&
                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK) &&
                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)
                ) {
                    String fieldType = JdbcToJavaUtil.getClassName(column);
                    if (StrUtil.equalsIgnoreCase(fieldType, "LocalDateTime")) {
                        Optional<ComponentConfig> componentConfig = componentConfigList.stream().filter(config ->
                                StrUtil.equalsIgnoreCase(column.getName(), config.getBindField()) ||
                                        StrUtil.equalsIgnoreCase(column.getName(), config.getBindStartTime()) ||
                                        StrUtil.equalsIgnoreCase(column.getName(), config.getBindEndTime())
                        ).findFirst();
                        componentConfig.ifPresent(config -> {
                            String format = MapUtils.getString(config.getOptions(), "format");
                            if (StrUtil.isNotEmpty(format)) {
                                fieldConfig.setPattern(LocalDateTimeUtil.convertFontFormat(format));
                            }
                        });
                    }
                    fieldConfig.setFieldComment(column.getComment());
                    fieldConfig.setPk(false);
                    fieldConfig.setFieldType(fieldType);
                    fieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(column.getName()));

                    fieldConfigList.add(fieldConfig);

                }

            }


            //如果有子表  每多一个子表  多加2个长度
            Map<String, Object> entityMap = new HashMap<>(8 + (tableInfos.size() - 1) * 2);
            entityMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "dto");
            entityMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
            entityMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            entityMap.put(EntityConstant.TABLE_NAME, tableInfo.getTableName());
            entityMap.put(EntityConstant.TABLE_COMMENT, generatorConfig.getOutputConfig().getComment());
            //先将表明转换为驼峰命名 然后在转换为首字母大写
            entityMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
            entityMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
            entityMap.put(EntityConstant.OUTPUT_AREA, generatorConfig.getOutputConfig().getOutputValue());

            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
            boolean isMainTable = generatorConfig.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
            if (tableInfos.size() > 1 && isMainTable) {
                List<TableConfig> childTables = generatorConfig.getTableConfigs().stream()
                        .filter(x -> !x.getIsMain())
                        .collect(Collectors.toList());
                List<TableConfig> newChildTables = new ArrayList<>();
                for (TableConfig childTable : childTables) {
                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);

                    newTableConfig.setRelationField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationField()));
                    newTableConfig.setRelationTableField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationTableField()));
                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));

                    newChildTables.add(newTableConfig);
                }
//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
                entityMap.put(EntityConstant.CHILD_TABLES, newChildTables);
//                parentTable.ifPresent(x -> entityMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
            }


            //生产目标代码
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//            Template template = configuration.getTemplate(ADD_DTO_TEMPLATE_NAME);

            FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(ADD_DTO_TEMPLATE_NAME);
            String entityContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, entityMap);

            addCodeMap.put("Add" + StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Dto", entityContent);
        }

        return addCodeMap;
    }

    /**
     * 根据配置修改dto代码
     *
     * @param generatorConfig 入参
     * @param tableInfos      表信息
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getUpdateDtoCode(GeneratorConfig generatorConfig, List<Table> tableInfos) {
        Map<String, String> updateCodeMap = new HashMap<>(tableInfos.size());
        Map<String, List<ComponentConfig>> tableFieldListMap = GeneratorUtil.buildFormComponentList(generatorConfig.getFormJson().getList());
        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
        for (Table tableInfo : tableInfos) {

            //获取表的所有字段
            Collection<Column> columns = tableInfo.getColumns();
            List<FieldConfig> fieldConfigList = new ArrayList<>();

            List<ComponentConfig> componentConfigList = tableFieldListMap.get(tableInfo.getTableName());
            for (Column column : columns) {
                FieldConfig fieldConfig = new FieldConfig();

//                boolean isMainTable = generatorConfig.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
                //子表的 UpdateDto 不需要主键
//                if (column.isPk() && !isMainTable) {
//                    continue;
//                }

                //不属于 固定的审计字段 都需要生成
                if (
                        !GlobalConstant.AUTO_INSERT.contains(column.getName()) &&
                                !GlobalConstant.AUTO_UPDATE.contains(column.getName()) &&
                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK) &&
                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)
                ) {
                    String fieldType = JdbcToJavaUtil.getClassName(column);
                    if (StrUtil.equalsIgnoreCase(fieldType, "LocalDateTime")) {
                        Optional<ComponentConfig> componentConfig = componentConfigList.stream().filter(config ->
                                StrUtil.equalsIgnoreCase(column.getName(), config.getBindField()) ||
                                        StrUtil.equalsIgnoreCase(column.getName(), config.getBindStartTime()) ||
                                        StrUtil.equalsIgnoreCase(column.getName(), config.getBindEndTime())
                        ).findFirst();
                        componentConfig.ifPresent(config -> {
                            String format = MapUtils.getString(config.getOptions(), "format");
                            if (StrUtil.isNotEmpty(format)) {
                                fieldConfig.setPattern(LocalDateTimeUtil.convertFontFormat(format));
                            }
                        });
                    }
                    fieldConfig.setFieldComment(column.getComment());
                    fieldConfig.setPk(false);
                    fieldConfig.setFieldType(fieldType);
                    fieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(column.getName()));

                    fieldConfigList.add(fieldConfig);

                }

            }


            //如果有子表  每多一个子表  多加2个长度
            Map<String, Object> entityMap = new HashMap<>(8 + (tableInfos.size() - 1) * 2);
            entityMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "dto");
            entityMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
            entityMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            entityMap.put(EntityConstant.TABLE_NAME, tableInfo.getTableName());
            entityMap.put(EntityConstant.TABLE_COMMENT, generatorConfig.getOutputConfig().getComment());
            //先将表明转换为驼峰命名 然后在转换为首字母大写
            entityMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
            entityMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);

            entityMap.put(EntityConstant.OUTPUT_AREA, generatorConfig.getOutputConfig().getOutputValue());

            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
            boolean isMainTable = generatorConfig.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
            if (tableInfos.size() > 1 && isMainTable) {
                List<TableConfig> childTables = generatorConfig.getTableConfigs().stream()
                        .filter(x -> !x.getIsMain())
                        .collect(Collectors.toList());
                List<TableConfig> newChildTables = new ArrayList<>();
                for (TableConfig childTable : childTables) {
                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);

                    newTableConfig.setRelationField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationField()));
                    newTableConfig.setRelationTableField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationTableField()));
                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));

                    newChildTables.add(newTableConfig);
                }
//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
                entityMap.put(EntityConstant.CHILD_TABLES, newChildTables);
//                parentTable.ifPresent(x -> entityMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
            }

            //生产目标代码
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//            Template template = configuration.getTemplate(UPDATE_DTO_TEMPLATE_NAME);
            FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(UPDATE_DTO_TEMPLATE_NAME);
            String entityContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, entityMap);

            updateCodeMap.put("Update" + StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Dto", entityContent);
        }

        return updateCodeMap;
    }


    /**
     * 根据配置生成 分页入参dto代码
     *
     * @param generatorConfig 入参
     * @param tableInfos      表信息
     * @param mainTable       主表配置
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getPageDtoCode(GeneratorConfig generatorConfig, List<Table> tableInfos, TableConfig mainTable) {
        List<QueryConfig> queryConfigs = generatorConfig.getListConfig().getQueryConfigs();

        List<FieldConfig> queryFieldConfigList = new ArrayList<>();

        Optional<Table> mainTableInfoOptional = tableInfos.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getTableName(), mainTable.getTableName())).findFirst();
        for (QueryConfig queryConfig : queryConfigs) {
            if (mainTableInfoOptional.isPresent()) {
                Table mainTableInfo = mainTableInfoOptional.get();
                Optional<Column> first = mainTableInfo.getColumns().stream().filter(x -> StrUtil.equalsIgnoreCase(x.getName(), queryConfig.getFieldName())).findFirst();
                first.ifPresent(x -> {
                    //如果是日期类型 默认设置查询参数为两个
                    if (queryConfig.getIsDate()) {
                        //开始时间
                        FieldConfig startConfig = new FieldConfig();
                        startConfig.setPk(false);
                        startConfig.setFieldComment(x.getComment() + "字段开始时间");
                        startConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(x.getName()) + "Start");
                        startConfig.setFieldType(JdbcToJavaUtil.getClassName(x));
                        queryFieldConfigList.add(startConfig);

                        //结束时间
                        FieldConfig endConfig = new FieldConfig();
                        endConfig.setPk(false);
                        endConfig.setFieldComment(x.getComment() + "字段结束时间");
                        endConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(x.getName()) + "End");
                        endConfig.setFieldType(JdbcToJavaUtil.getClassName(x));
                        queryFieldConfigList.add(endConfig);
                    } else {
                        //默认插入主键字段 放在第一个
                        FieldConfig queryFieldConfig = new FieldConfig();
                        queryFieldConfig.setPk(false);
                        queryFieldConfig.setFieldComment(x.getComment());
                        queryFieldConfig.setFieldType(JdbcToJavaUtil.getClassName(x));
                        queryFieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(x.getName()));
                        queryFieldConfigList.add(queryFieldConfig);
                    }

                });

            } else {
                throw new MyException("没有主表");
            }


        }

        // 是否有左侧菜单 如果有左侧菜单  再queryconfig里面 新增一个查询字段  用于左侧菜单点击后 带参数查询
        if (generatorConfig.getListConfig().getIsLeftMenu()) {
            String fieldName = generatorConfig.getListConfig().getLeftMenuConfig().getListFieldName();

            //查询条件是否包含此字段
            boolean b = queryConfigs.stream().anyMatch(x -> StrUtil.equals(x.getFieldName(), fieldName));
            //如果未包含 则新增一个查询字段
            if (!b) {
                Optional<Table> mainTableInfoOp = tableInfos.stream().filter(x -> StrUtil.equals(x.getTableName(), mainTable.getTableName())).findFirst();
                mainTableInfoOp.ifPresent(x -> {
                    //获取当前主表的所有字段
                    Collection<Column> columns = x.getColumns();
                    //获取到当前左侧树 的查询字段 类型
                    Optional<Column> leftQueryField = columns.stream().filter(column -> StrUtil.equals(fieldName, column.getName())).findFirst();

                    //默认插入左侧树查询字段
                    leftQueryField.ifPresent(column -> {

                        FieldConfig queryFieldConfig = new FieldConfig();
                        queryFieldConfig.setPk(false);
                        queryFieldConfig.setFieldComment(x.getComment());
                        queryFieldConfig.setFieldType(JdbcToJavaUtil.getClassName(column));
                        queryFieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(fieldName));
                        queryFieldConfigList.add(queryFieldConfig);
                    });
                });

            }
        }

        Map<String, Object> queryMap = new HashMap<>(7);
        queryMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "dto");
        queryMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
        queryMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        queryMap.put(EntityConstant.TABLE_COMMENT, generatorConfig.getListConfig().getIsPage() ? "分页查询入参" : "列表查询入参");
        queryMap.put(EntityConstant.IS_PAGE, generatorConfig.getListConfig().getIsPage());
        //先将表明转换为驼峰命名 然后在转换为首字母大写
        queryMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTable.getTableName())));
        queryMap.put(EntityConstant.TABLE_FIELDS, queryFieldConfigList);

        //生产目标代码
//        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//        configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//        Template template = configuration.getTemplate(PAGE_DTO_TEMPLATE_NAME);
        FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(PAGE_DTO_TEMPLATE_NAME);

        String pageDtoConent = FreeMarkerTemplateUtils.processTemplateIntoString(template, queryMap);

        Map<String, String> map = new HashMap<>(1);
        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(mainTable.getTableName())) + (generatorConfig.getListConfig().getIsPage() ? "Page" : "List") + "Dto", pageDtoConent);

        return map;
    }

    /**
     * 根据配置生成 列表页Vo代码
     *
     * @param generatorConfig 入参
     * @param tableInfos      表信息
     * @param mainTableConfig 主表配置
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getPageVoCode(GeneratorConfig generatorConfig, List<Table> tableInfos, TableConfig mainTableConfig) {
        List<ColumnConfig> columnConfigs = generatorConfig.getListConfig().getColumnConfigs();
        //获取表的所有字段
        Optional<Table> mainTableOp = tableInfos.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getTableName(), mainTableConfig.getTableName())).findFirst();

        Table mainTable;
        if (mainTableOp.isPresent()) {
            mainTable = mainTableOp.get();
        } else {
            throw new MyException("没有主表");
        }

        Collection<Column> columns = mainTable.getColumns();


        List<FieldConfig> fieldConfigList = new ArrayList<>();

        Map<String, List<ComponentConfig>> tableFieldConfigList = GeneratorUtil.buildFormComponentList(generatorConfig.getFormJson().getList());
        List<ComponentConfig> mainTableFieldConfigList = tableFieldConfigList.get(mainTable.getTableName());
        for (Column column : columns) {

            //列表配置有  就需要添加
            if (columnConfigs.stream().anyMatch(x -> StrUtil.equalsIgnoreCase(column.getName(), x.getColumnName())) || column.isPk()) {
                FieldConfig fieldConfig = new FieldConfig();
                fieldConfig.setFieldComment(column.getComment());
                fieldConfig.setPk(false);
                //如果是主键 就默认使用字符串类型 前端无法识别long类型的精度
                fieldConfig.setFieldType(column.isPk() ? "String" : JdbcToJavaUtil.getClassName(column));
                fieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(column.getName()));
                // 表单配置
                if (!column.isPk()) {
                    ComponentConfig componentConfig = mainTableFieldConfigList.stream().filter(config ->
                            StrUtil.equalsIgnoreCase(column.getName(), config.getBindField()) ||
                                    StrUtil.equalsIgnoreCase(column.getName(), config.getBindStartTime()) ||
                                    StrUtil.equalsIgnoreCase(column.getName(), config.getBindEndTime())
                    ).findFirst().get();
                    String componentType = componentConfig.getType();
                    Map<String, Object> options = componentConfig.getOptions();
                    if (StrUtil.equalsIgnoreCase(componentType, ComponentTypeConstant.INFO)) {
                        Integer infoType = MapUtils.getInteger(options, "infoType");
                        String toType = null;
                        switch (infoType) {
                            case 0:
                                toType = "user";
                                break;
                            case 1:
                                toType = "organization";
                                break;
                            case 2:
                                toType = "datetime";
                                break;
                        }
                        fieldConfig.setComponentType(toType);
                    } else {
                        fieldConfig.setComponentType(componentType);
                    }
                    String datasourceType = MapUtils.getString(options, "datasourceType");
                    if (!StrUtil.isEmpty(datasourceType)) {
                        fieldConfig.setDatasourceType(datasourceType);
                        String datasourceId = null;
                        if (StrUtil.equalsIgnoreCase(datasourceType, "dic")) {
                            datasourceId = MapUtils.getString(options, "itemId");
                        } else if (StrUtil.equalsIgnoreCase(datasourceType, "api")) {
                            datasourceId = MapUtils.getString(MapUtils.getMap(options, "apiConfig"), "apiId");
                        }
                        fieldConfig.setDatasourceId(datasourceId);
                    }
                    String format = MapUtils.getString(options, "format");
                    if (StrUtil.isNotEmpty(format)) {
                        fieldConfig.setPattern(LocalDateTimeUtil.convertFontFormat(format));
                    }
                    // 多选值组件
                    if (StrUtil.equalsIgnoreCase(componentType, ComponentTypeConstant.MULTIPLE_POPUP)
                            || StrUtil.equalsIgnoreCase(componentType, ComponentTypeConstant.CHECKBOX)
                            || (StrUtil.equalsIgnoreCase(componentType, ComponentTypeConstant.SELECT)
                            && MapUtils.getBoolean(options, "isMultiple", false))) {
                        fieldConfig.setMulti(true);
                    }
                    //级联
                    if (StrUtil.equalsIgnoreCase(componentType, ComponentTypeConstant.CASCADE)) {
                        fieldConfig.setSeparator(MapUtils.getString(options, ComponentTypeConstant.SEPARATOR));
                        fieldConfig.setShowFormat(MapUtils.getString(options, ComponentTypeConstant.SHOW_FORMAT));
                        fieldConfig.setDatasourceId(MapUtils.getString(MapUtils.getMap(options, "apiConfig"), "apiId"));
                    }
                    // 树组件
                    if (StrUtil.equalsIgnoreCase(componentType, ComponentTypeConstant.TREE_SELECT)) {
                        fieldConfig.setDatasourceId(MapUtils.getString(MapUtils.getMap(options, "treeConfig"), "id"));
                        fieldConfig.setMulti(MapUtils.getBoolean(MapUtils.getMap(options, "treeConfig"), "isMultiple", false));
                    }

                    // 设置时间范围和日期范围label
                    String label = componentConfig.getLabel();
                    if (StrUtil.equalsIgnoreCase(column.getName(), componentConfig.getBindStartTime())) {
                        label += "开始";
                    } else if (StrUtil.equalsIgnoreCase(column.getName(), componentConfig.getBindEndTime())) {
                        label += "结束";
                    }
                    fieldConfig.setLabel(label);
                    fieldConfig.setRequired(MapUtils.getBoolean(options, "required", false));
                } else {
                    fieldConfig.setPk(true);
                }
                fieldConfigList.add(fieldConfig);
                continue;
            }
            //列表添加数据权限字段返回
            if (BooleanUtils.isTrue(generatorConfig.getOutputConfig().getIsDataAuth()) && StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.AUTH_USER_ID)) {
                FieldConfig fieldConfig = new FieldConfig();
                fieldConfig.setFieldComment(column.getComment());
                fieldConfig.setPk(false);
                //如果是主键 就默认使用字符串类型 前端无法识别long类型的精度
                fieldConfig.setFieldType(column.isPk() ? "String" : JdbcToJavaUtil.getClassName(column));
                fieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(column.getName()));
                fieldConfigList.add(fieldConfig);
            }
        }


        Map<String, Object> columnMap = new HashMap<>(7);
        columnMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "vo");
        columnMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
        columnMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        columnMap.put(EntityConstant.TABLE_COMMENT, generatorConfig.getListConfig().getIsPage() ? "分页列表出参" : "列表列表入参");
        columnMap.put(EntityConstant.IS_PAGE, generatorConfig.getListConfig().getIsPage());
        //先将表明转换为驼峰命名 然后在转换为首字母大写
        columnMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTable.getTableName())));
        columnMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
        // 导入导出
        boolean isImport = false;
        boolean isExport = false;
        List<ButtonConfig> buttonConfigs = generatorConfig.getListConfig().getButtonConfigs();
        for (ButtonConfig config : buttonConfigs) {
            if (!isImport)
                isImport = StringUtils.equals(config.getCode(), ComponentTypeConstant.BUTTON_IMPORT) && config.getIsUse();
            if (!isExport)
                isExport = StringUtils.equals(config.getCode(), ComponentTypeConstant.BUTTON_EXPORT) && config.getIsUse();
        }
        columnMap.put(EntityConstant.IS_IMPORT, isImport);
        columnMap.put(EntityConstant.IS_EXPORT, isExport);
        columnMap.put(EntityConstant.REQUIRED_SUFFIX, ExcelUtil.EXPORT_REQUIRED_SUFFIX);


        //生产目标代码
//        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//        configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//        Template template = configuration.getTemplate(PAGE_VO_TEMPLATE_NAME);

        FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(PAGE_VO_TEMPLATE_NAME);

        String pageVoConent = FreeMarkerTemplateUtils.processTemplateIntoString(template, columnMap);

        Map<String, String> map = new HashMap<>(1);
        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(mainTable.getTableName())) + (generatorConfig.getListConfig().getIsPage() ? "Page" : "List") + "Vo", pageVoConent);

        return map;
    }

    /**
     * 根据配置生成 表单Vo代码
     *
     * @param generatorConfig 入参
     * @param tableInfos      表信息
     * @param mainTableConfig 主表配置
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getInfoVoCode(GeneratorConfig generatorConfig, List<Table> tableInfos, TableConfig mainTableConfig) {
        //获取表的所有字段
        Optional<Table> mainTableOp = tableInfos.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getTableName(), mainTableConfig.getTableName())).findFirst();

        Table mainTable;
        if (mainTableOp.isPresent()) {
            mainTable = mainTableOp.get();
        } else {
            throw new MyException("没有主表");
        }

        Map<String, String> infoVoMap = new HashMap<>(1);
        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
        for (Table tableInfo : tableInfos) {
            //获取表的所有字段
            Collection<Column> columns = tableInfo.getColumns();


            List<FieldConfig> fieldConfigList = new ArrayList<>();

            for (Column column : columns) {
                FieldConfig fieldConfig = new FieldConfig();

                //只要不是审计字段都返回去
                if (!GlobalConstant.AUTO_INSERT.contains(column.getName()) &&
                        !GlobalConstant.AUTO_UPDATE.contains(column.getName()) &&
                        !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK) &&
                        !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)) {

                    fieldConfig.setFieldComment(column.getComment());
                    fieldConfig.setPk(false);
                    fieldConfig.setFieldType(JdbcToJavaUtil.getClassName(column));
                    fieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(column.getName()));

                    fieldConfigList.add(fieldConfig);

                }
            }


            Map<String, Object> columnMap = new HashMap<>(7 + (tableInfos.size() - 1) * 1);
            columnMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "vo");
            columnMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
            columnMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            columnMap.put(EntityConstant.TABLE_COMMENT, "表单出参");
            //先将表明转换为驼峰命名 然后在转换为首字母大写
            columnMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
            columnMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);

            columnMap.put(EntityConstant.OUTPUT_AREA, generatorConfig.getOutputConfig().getOutputValue());

            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
            boolean isMainTable = generatorConfig.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
            if (tableInfos.size() > 1 && isMainTable) {
                List<TableConfig> childTables = generatorConfig.getTableConfigs().stream()
                        .filter(x -> !x.getIsMain())
                        .collect(Collectors.toList());
                List<TableConfig> newChildTables = new ArrayList<>();
                for (TableConfig childTable : childTables) {
                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);

                    newTableConfig.setRelationField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationField()));
                    newTableConfig.setRelationTableField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationTableField()));
                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));

                    newChildTables.add(newTableConfig);
                }
//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
                columnMap.put(EntityConstant.CHILD_TABLES, newChildTables);
//                parentTable.ifPresent(x -> columnMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
            }
            //生产目标代码
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//            Template template = configuration.getTemplate(INFO_VO_TEMPLATE_NAME);

            FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(INFO_VO_TEMPLATE_NAME);

            String infoVoConent = FreeMarkerTemplateUtils.processTemplateIntoString(template, columnMap);


            infoVoMap.put(StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Vo", infoVoConent);

        }

        return infoVoMap;
    }

    /**
     * 根据配置生成mapper文件
     *
     * @param generatorConfig 入参
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getMapperCode(GeneratorConfig generatorConfig, List<Table> tableInfos) {


        Map<String, String> map = new HashMap<>(1 + tableInfos.size() - 1);

        for (Table tableInfo : tableInfos) {

            Map<String, Object> mapperMap = new HashMap<>(7);
            mapperMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "mapper");
            mapperMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
            mapperMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
            mapperMap.put(EntityConstant.TABLE_COMMENT, "mapper");
            //先将表明转换为驼峰命名 然后在转换为首字母大写
            mapperMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
            mapperMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())));
            mapperMap.put(EntityConstant.OUTPUT_AREA, generatorConfig.getOutputConfig().getOutputValue());

            mapperMap.put(EntityConstant.IS_MULTI, tableInfos.size() > 1);

            //生产目标代码
//            Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//            configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//            configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//            Template template = configuration.getTemplate(MAPPPER_TEMPLATE_NAME);
            FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(MAPPPER_TEMPLATE_NAME);

            String mapperContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, mapperMap);

            map.put(StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Mapper", mapperContent);

        }


        return map;
    }

    /**
     * 根据配置生成service文件
     *
     * @param generatorConfig 入参
     * @param mainTableConfig 主表配置
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getServiceCode(GeneratorConfig generatorConfig, TableConfig mainTableConfig, Boolean isMulti) {
        Map<String, Object> serviceMap = new HashMap<>(7);
        serviceMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "service");
        serviceMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
        serviceMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        serviceMap.put(EntityConstant.TABLE_COMMENT, "service");
        //先将表明转换为驼峰命名 然后在转换为首字母大写
        serviceMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
        serviceMap.put(EntityConstant.OUTPUT_AREA, generatorConfig.getOutputConfig().getOutputValue());
        serviceMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())));
        serviceMap.put(EntityConstant.IS_MULTI, isMulti);
        serviceMap.put(EntityConstant.PK_TYPE, mainTableConfig.getPkType());

        //生产目标代码
//        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//        configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//        Template template = configuration.getTemplate(SERVICE_TEMPLATE_NAME);
        FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(SERVICE_TEMPLATE_NAME);

        String serviceContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, serviceMap);

        Map<String, String> map = new HashMap<>(1);
        map.put("I" + StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())) + "Service", serviceContent);
        return map;
    }


    /**
     * 根据配置生成service impl代码
     *
     * @param generatorConfig 入参
     * @param mainTableConfig 主表配置
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getServiceImplCode(GeneratorConfig generatorConfig, TableConfig mainTableConfig, Boolean isMulti) {
        Optional<TableConfig> first = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
        if (!first.isPresent()) {
            throw new MyException("未设置主表！");
        }

        Map<String, Object> serviceMap = new HashMap<>(8);
        serviceMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "service.impl");
        serviceMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
        serviceMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        serviceMap.put(EntityConstant.TABLE_COMMENT, "service");
        serviceMap.put(EntityConstant.PARENT_TABLE_KEY, first.get().getPkField());
        //先将表明转换为驼峰命名 然后在转换为首字母大写
        serviceMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
        serviceMap.put(EntityConstant.OUTPUT_AREA, generatorConfig.getOutputConfig().getOutputValue());
        serviceMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())));

        serviceMap.put(EntityConstant.IS_MULTI, isMulti);
        serviceMap.put(EntityConstant.PK_TYPE, mainTableConfig.getPkType());
        serviceMap.put(EntityConstant.DATASOURCE_ID, generatorConfig.getDatabaseId());

        //传入所有子表
        List<TableConfig> childTables = generatorConfig.getTableConfigs().stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());

        List<TableConfig> newChildTables = new ArrayList<>();
        for (TableConfig childTable : childTables) {
            TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);

            newTableConfig.setRelationField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationField()));
            newTableConfig.setRelationTableField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getRelationTableField()));
            newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));
            newTableConfig.setPkField(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(childTable.getPkField()));
            newTableConfig.setPkType(childTable.getPkType());

            newChildTables.add(newTableConfig);
        }

        serviceMap.put(EntityConstant.CHILD_TABLES, newChildTables);

        //生产目标代码
//        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//        configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//        Template template = configuration.getTemplate(SERVICE_IMPL_TEMPLATE_NAME);
        FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(SERVICE_IMPL_TEMPLATE_NAME);

        String serviceImplContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, serviceMap);

        Map<String, String> map = new HashMap<>(1);
        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())) + "ServiceImpl", serviceImplContent);
        return map;
    }


    /**
     * 根据配置生成控制器代码
     *
     * @param generatorConfig 入参
     * @param mainTableConfig 主表配置
     * @return 代码
     */
    @SneakyThrows
    public static Map<String, String> getControllerCode(GeneratorConfig generatorConfig, List<Table> tableInfos, TableConfig mainTableConfig) {

        List<QueryConfig> queryConfigs = generatorConfig.getListConfig().getQueryConfigs();

        List<FieldConfig> queryFieldConfigList = new ArrayList<>();
        Table mainTableInfo = null;
        Optional<Table> mainTableInfoOptional = tableInfos.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getTableName(), mainTableConfig.getTableName())).findFirst();
        if (mainTableInfoOptional.isPresent()) {
            mainTableInfo = mainTableInfoOptional.get();
        } else {
            throw new MyException("没有主表");
        }
        for (QueryConfig queryConfig : queryConfigs) {

            //如果是日期类型 默认设置查询参数为两个
            if (queryConfig.getIsDate()) {

                FieldConfig dateConfig = new FieldConfig();
                dateConfig.setPk(false);
                dateConfig.setFieldComment(queryConfig.getFieldName() + "字段");
                dateConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(queryConfig.getFieldName()));
                dateConfig.setFieldType(LocalDateTime.class.getName().replace("java.time.", ""));
                queryFieldConfigList.add(dateConfig);
            } else {
                Optional<Column> first = mainTableInfo.getColumns().stream().filter(x -> StrUtil.equalsIgnoreCase(x.getName(), queryConfig.getFieldName())).findFirst();
                if (first.isPresent()) {
                    Column x = first.get();
                    //默认插入主键字段 放在第一个
                    FieldConfig fieldConfig = new FieldConfig();
                    fieldConfig.setPk(x.isPk());
                    fieldConfig.setFieldComment(x.getComment());
                    fieldConfig.setFieldType(JdbcToJavaUtil.getClassName(x));
                    String fieldName = com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(x.getName());
                    fieldConfig.setFieldName(fieldName);
                    queryFieldConfigList.add(fieldConfig);
                }



            }
        }

        // 是否有左侧菜单 如果有左侧菜单  再queryconfig里面 新增一个查询字段  用于左侧菜单点击后 带参数查询
//        if (generatorConfig.getListConfig().getIsLeftMenu()) {
//            String fieldName = generatorConfig.getListConfig().getLeftMenuConfig().getListFieldName();
//
//            //查询条件是否包含此字段
//            boolean b = queryConfigs.stream().anyMatch(x -> StrUtil.equals(x.getFieldName(), fieldName));
//            //如果未包含 则新增一个查询字段
//            if (!b) {
//                Optional<Table> mainTableInfoOp = tableInfos.stream().filter(x -> StrUtil.equals(x.getTableName(), mainTableConfig.getTableName())).findFirst();
//                mainTableInfoOp.ifPresent(x -> {
//                    //获取当前主表的所有字段
//                    Collection<Column> columns = x.getColumns();
//                    //获取到当前左侧树 的查询字段 类型
//                    Optional<Column> leftQueryField = columns.stream().filter(column -> StrUtil.equals(fieldName, column.getName())).findFirst();
//
//                    //默认插入左侧树查询字段
//                    leftQueryField.ifPresent(column -> {
//
//                        FieldConfig queryFieldConfig = new FieldConfig();
//                        queryFieldConfig.setPk(false);
//                        queryFieldConfig.setFieldComment(x.getComment());
//                        queryFieldConfig.setFieldType(JdbcToJavaUtil.getClassName(column));
//                        queryFieldConfig.setFieldName(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(fieldName));
//                        queryFieldConfigList.add(queryFieldConfig);
//                    });
//                });
//
//            }
//        }
        // 找出自动编码code
        StringBuilder autoCode = new StringBuilder();
        Map<String, List<ComponentConfig>> componentListMap = GeneratorUtil.buildFormComponentList(generatorConfig.getFormJson().getList());
        for (List<ComponentConfig> componentList : componentListMap.values()) {
            for (ComponentConfig componentConfig : componentList) {
                if (StrUtil.equalsIgnoreCase(componentConfig.getType(), ComponentTypeConstant.AUTO_CODE)) {
                    String codeRule = MapUtils.getString(componentConfig.getOptions(), ComponentTypeConstant.AUTO_CODE_RULE);
                    if (StrUtil.isNotEmpty(codeRule)) {
                        autoCode.append(codeRule);
                        autoCode.append(StringPool.COMMA);
                    }
                }
            }
        }
        if (autoCode.length() > 1) autoCode.deleteCharAt(autoCode.length() - 1);

        Map<String, Object> controllerMap = new HashMap<>(12);
        controllerMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + generatorConfig.getOutputConfig().getOutputValue() + StringPool.DOT + "controller");
        controllerMap.put(EntityConstant.AUTH_NAME, generatorConfig.getOutputConfig().getCreator());
        controllerMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        controllerMap.put(EntityConstant.TABLE_COMMENT, generatorConfig.getOutputConfig().getComment());
        controllerMap.put(EntityConstant.IS_PAGE, generatorConfig.getListConfig().getIsPage());
        //先将表名转换为驼峰命名 然后在转换为首字母大写
        controllerMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
        controllerMap.put(EntityConstant.OUTPUT_AREA, generatorConfig.getOutputConfig().getOutputValue());
        controllerMap.put(EntityConstant.TABLE_FIELDS, queryFieldConfigList);
        controllerMap.put(EntityConstant.PK_FIELD, com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(mainTableConfig.getPkField()));
        controllerMap.put(EntityConstant.PK_TYPE, mainTableConfig.getPkType());
        controllerMap.put(EntityConstant.IS_MULTI, tableInfos.size() > 1);
        controllerMap.put(EntityConstant.CODE_RULES, autoCode.toString());
        controllerMap.put(EntityConstant.IS_LEFT_MENU, generatorConfig.getListConfig().getIsLeftMenu());

        controllerMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())));

        String orderType = null;
        String orderField = null;
        if (generatorConfig.getListConfig().getDefaultOrder()) {
            orderType = "desc";
            orderField = com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(mainTableInfo.getPkNames().iterator().next());
        } else {
            orderType = generatorConfig.getListConfig().getOrderType();
            orderField = com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(generatorConfig.getListConfig().getOrderBy());
        }
        controllerMap.put(EntityConstant.ORDER_TYPE, StrUtil.equalsIgnoreCase(orderType, "desc"));
        controllerMap.put(EntityConstant.ORDER_FIELD, StrUtil.upperFirst(orderField));
        controllerMap.put(EntityConstant.IS_DATA_AUTH, BooleanUtils.isTrue(generatorConfig.getOutputConfig().getIsDataAuth()));
        // 导入导出
        boolean isImport = false;
        boolean isExport = false;
        List<ButtonConfig> buttonConfigs = generatorConfig.getListConfig().getButtonConfigs();
        for (ButtonConfig config : buttonConfigs) {
            if (!isImport)
                isImport = StrUtil.equals(config.getCode(), ComponentTypeConstant.BUTTON_IMPORT) && config.getIsUse();
            if (!isExport)
                isExport = StrUtil.equals(config.getCode(), ComponentTypeConstant.BUTTON_EXPORT) && config.getIsUse();
        }
        controllerMap.put(EntityConstant.IS_IMPORT, isImport);
        controllerMap.put(EntityConstant.IS_EXPORT, isExport);

        //生产目标代码
//        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
//        configuration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
//        Template template = configuration.getTemplate(CONTROLLER_TEMPLATE_NAME);
        FreeMarkerConfigurer freeMarkerConfigurer = SpringUtil.getBean(FreeMarkerConfigurer.class);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(CONTROLLER_TEMPLATE_NAME);

        String controllerContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, controllerMap);

        Map<String, String> map = new HashMap<>(1);
        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())) + "Controller", controllerContent);
        return map;
    }

    /**
     * 获取生成目录 默认生成到src/main/java/com/xjrsoft/module
     *
     * @return
     */
    public static String getOutputDir() {
        return System.getProperty("user.dir") + StringPool.SLASH + "src" + StringPool.SLASH + "main" + StringPool.SLASH + "java" + StringPool.SLASH + "com" + StringPool.SLASH + "xjrsoft" + StringPool.SLASH + "module";
    }

    /**
     * 获取实体类生成目录
     *
     * @param outputArea
     * @return
     */
    public static String getEntityOutputDir(String outputArea) {
        return getOutputDir() + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + "entity";
    }

    /**
     * 获取dto的生成目录
     *
     * @param outputArea
     * @return
     */
    public static String getDtoOutputDir(String outputArea) {
        return getOutputDir() + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + "dto";
    }

    /**
     * 获取vo的输出目录
     *
     * @param outputArea
     * @return
     */
    public static String getVoOutputDir(String outputArea) {
        return getOutputDir() + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + "vo";
    }

    /**
     * 获取mapper的输出目录
     *
     * @param outputArea
     * @return
     */
    public static String getMapperOutputDir(String outputArea) {
        return getOutputDir() + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + "mapper";
    }

    /**
     * 获取service的生成目录
     *
     * @param outputArea
     * @return
     */
    public static String getServiceOutputDir(String outputArea) {
        return getOutputDir() + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + "service";
    }

    /**
     * 获取serviceImpl的生成目录
     *
     * @param outputArea
     * @return
     */
    public static String getServiceImplOutputDir(String outputArea) {
        return getOutputDir() + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + "service" + StringPool.SLASH + "impl";
    }

    /**
     * 获取控制器生成目录
     *
     * @param outputArea
     * @return
     */
    public static String getControllerOutputDir(String outputArea) {
        return getOutputDir() + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + "controller";
    }

    public static void writeFile(String dirPath, String fileName, String content) throws FileNotFoundException {
        File dir = new File(dirPath);
        if (!dir.exists()) {
            boolean mkdirs = dir.mkdirs();
        }
        String filePath = dirPath + StringPool.SLASH + fileName;
        File javaFile = new File(filePath);
        if (javaFile.exists()) {
            javaFile.renameTo(new File(dirPath + StringPool.SLASH + fileName + StringPool.DOT + System.currentTimeMillis() + ".bak"));
        }
        FileOutputStream voFile = new FileOutputStream(filePath);
        IoUtil.write(voFile, true, content.getBytes(StandardCharsets.UTF_8));
    }

}
